package com.rocky.component.elasticsearch;

import com.rocky.component.util.ObjectMapperUtil;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.query.ExistsQueryBuilder;
import org.elasticsearch.index.query.FuzzyQueryBuilder;
import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.PrefixQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.index.query.WildcardQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

/**
 * @author rocky
 * date 2025-07-18
 * Description:
 */
@RestController
@RequestMapping("/termLevelQuery")
public class TermLevelQueryExample {

    private final RestHighLevelClient restHighLevelClient;

    public TermLevelQueryExample(RestHighLevelClient restHighLevelClient) {
        this.restHighLevelClient = restHighLevelClient;
    }

    @GetMapping("/termQuery")
    public String termQuery() throws IOException {
        TermQueryBuilder queryBuilder = QueryBuilders.termQuery("address.keyword", "735 Losee Terrace");    // keyword 防止分词

        return search(queryBuilder);
    }

    @GetMapping("/termsQuery")
    public String termsQuery() throws IOException {
        TermsQueryBuilder queryBuilder = QueryBuilders.termsQuery("address.keyword", "735 Losee Terrace", "440 Fuller Place");


        return search(queryBuilder);
    }

    @GetMapping("/rangeQuery")
    public String rangeQuery() throws IOException {
        RangeQueryBuilder queryBuilder = QueryBuilders.rangeQuery("age")
                .from(18)
                .to(36)
                .includeLower(true)
                .includeUpper(true);

        FieldSortBuilder sortBuilder = SortBuilders.fieldSort("age").order(SortOrder.DESC);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(queryBuilder)
                .sort(sortBuilder)
                .from(0)
                .size(5);

        SearchRequest searchRequest = new SearchRequest("bank").source(searchSourceBuilder);

        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        return ObjectMapperUtil.get().writeValueAsString(searchResponse.getHits());
    }

    @GetMapping("/existsQuery")
    public String existsQuery() throws IOException {
        ExistsQueryBuilder queryBuilder = QueryBuilders.existsQuery("age");

        return search(queryBuilder);
    }

    @GetMapping("/prefixQuery")
    public String prefixQuery() throws IOException {
        // 类似于 match_phrase_prefix 但纯在不同，前者是基于短语的前缀匹配，当前是基于全文本前缀的匹配
        PrefixQueryBuilder queryBuilder = QueryBuilders.prefixQuery("address.keyword", "334 River");

        return search(queryBuilder);
    }

    @GetMapping("/wildcardQuery")
    public String wildcardQuery() throws IOException {
        WildcardQueryBuilder queryBuilder = QueryBuilders.wildcardQuery("address", "Rive?");    // ? 匹配单个字符
//        WildcardQueryBuilder queryBuilder = QueryBuilders.wildcardQuery("address", "Rive*");    // * 匹配多个字符

        return search(queryBuilder);
    }

    @GetMapping("/fuzzyQuery")
    public String fuzzyQuery() throws IOException {
        FuzzyQueryBuilder queryBuilder = QueryBuilders.fuzzyQuery("address", "Raverdale")
                .fuzziness(Fuzziness.AUTO);

        return search(queryBuilder);
    }

    @GetMapping("/idsQuery")
    public String idsQuery() throws IOException {
        IdsQueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds("1", "6");

        return search(queryBuilder);
    }

    private String search(QueryBuilder queryBuilder) throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(queryBuilder);

        SearchRequest searchRequest = new SearchRequest("bank")
                .source(searchSourceBuilder);

        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        return ObjectMapperUtil.get().writeValueAsString(searchResponse.getHits());
    }
}
